package com.kfm.hotel.config;

import com.fasterxml.jackson.databind.json.JsonMapper;
import com.kfm.hotel.filter.MyUsernamePasswordAuthenticationFilter;
import com.kfm.hotel.service.SysUserService;
import com.kfm.hotel.util.Constant;
import com.kfm.hotel.util.R;
import org.assertj.core.api.Fail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

// 启用 Spring Security
@EnableWebSecurity
// 启用全局方法权限控制. prePostEnabled 启用全局方法权限控制, securedEnabled 启用 @Secured 注解权限控制
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {

    /**
     * 配置 HttpSecurity
     * @param http
     * @return
     * @throws Exception
     *  httpSecurity.authorizeRequests()
           antMatchers() 方法用于匹配路径
           permitAll() 方法用于配置该路径不需要权限即可访问
           anyRequest() 其余所有的请求都需要认证后才能访问
        httpSecurity.formLogin()  登录表单
            loginPage() 登录页面， 默认为 /login
            loginProcessingUrl() 登录请求处理接口， 默认为 /login
            usernameParameter("name") 登录用户名参数, request.getParmeter("name"), 默认 username
            passwordParameter("pwd") 登录密码参数, 默认 password
            successHandler() 登录成功处理器
            failureHandler() 登录失败处理器
            failureForwardUrl() 登录失败跳转页面
        httpSecurity.logout() 退出登录
            logoutUrl() 退出登录请求接口, 默认为 /logout
            logoutSuccessUrl() 退出登录成功跳转页面
        httpSecurity.csrf() 配置 csrf
            disable() 禁用 csrf
    httpSecurity.headers().frameOptions().sameOrigin() 配置允许同源的 iframe
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/", "/login","/captcha/**", "/captcha/get", "/images/**", "/static/**", "/webjars/**").permitAll()
                .anyRequest().authenticated()
                .and()
                // 配置登录页面
                .formLogin()
                .loginPage("/login") // 登录页面
                .loginProcessingUrl("/login") // 登录请求处理接口
                .usernameParameter("username") // 登录用户名参数, request.getParmeter(username)
                .passwordParameter("password") // 登录密码参数
                .and()
                .logout()
                .logoutUrl("/logout")
                .addLogoutHandler((req, resp, authentication) -> {
                    // 退出登录，删除session中的用户信息
                    req.getSession().removeAttribute(Constant.LOGIN_USER);
                    // 退出登录，删除cookie
                    Cookie cookie = new Cookie(Constant.REMEMBER_ME_COOKIE_NAME, "");
                    cookie.setMaxAge(0);
                    cookie.setPath("/");
                    resp.addCookie(cookie);
                })
                .logoutSuccessUrl("/login")
                .and().csrf().disable()
                .headers().frameOptions().sameOrigin()
                ;


        // 注入自定义的过滤器, 替换 UsernamePasswordAuthenticationFilter 过滤器
        MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter = new MyUsernamePasswordAuthenticationFilter(authenticationManager(http));
        myUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler((req, resp, auth) -> {
            req.getSession().setAttribute(Constant.LOGIN_USER, auth.getPrincipal());
            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(new JsonMapper().writeValueAsString(R.ok("登录成功", "index")));
        });
        myUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler((req, resp, auth) -> {
            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(new JsonMapper().writeValueAsString(R.fail("登录失败")));
        });
        http.addFilterAt(myUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        //注入新的AuthenticationManager
        http.authenticationManager(authenticationManager(http));
        return http.build();
    }

//    @Bean
//    public WebSecurityCustomizer ignoringCustomizer() {
//        return (web) -> web.ignoring().antMatchers("/captcha/**", "/captcha/get", "/images/**", "/static/**", "/webjars/**");
//    }


    @Autowired
    private SysUserService sysUserService;

    /**
     *密码加密规则
     */
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder(12);
//    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     *构造一个AuthenticationManager，使用自定义的userDetailsService和passwordEncoder
     */
    @Bean
    AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class)
                // 自定义userDetailsService，从数据库中读取用户信息
                .userDetailsService(sysUserService)
                .passwordEncoder(passwordEncoder())
                .and()
                .build();
        return authenticationManager;
    }


}

